use rand::Rng;
use std::collections::HashMap;
use std::fs;
use std::io;

mod math;

struct Player {
    inventory: [u32; 10],
    stamina: u32,
    health: u32,
    hunger: u32,
    pos: (usize, usize),
}

impl Player {
    fn new() -> Player {
        let mut rng = rand::thread_rng();
        let p = Player {
            inventory: [0; 10],
            stamina: 100,
            health: 100,
            hunger: 100,
            pos: (rng.gen_range(0..100), rng.gen_range(0..100)),
        };
        p
    }

    fn mv(&mut self,x: usize, y: usize) {
        let range = 0..100;
        self.pos = (math::clamp(x.to_owned(), 0, 100), math::clamp(y.to_owned(), 0, 100));
    }

    fn look_around(current_tile: MapTile) {
        match current_tile.tile_type {
            0 => todo!(), 
            _ => todo!(),
        }
    }
}

pub struct MapTile {
    tile_types: HashMap<String, u32>,
    tile_type: u32,
    items: [u32; 10],
    enemies: [u32; 10],
}

impl MapTile {
    fn new(t: u32, i: [u32; 10], e: [u32; 10]) -> MapTile{
        let m: MapTile = MapTile { 
            tile_types: HashMap::from([
            ("Plain".to_string(), 0),
            ("Field".to_string(), 1),
            ]),
            tile_type: t,
            items: i,
            enemies: e, 
        };
        m
    }

    fn translate_type(&self, key: String) -> u32{
        self.tile_types[&key]
    }

    fn get_type(val: u32) -> String{
        let temp = MapTile::new(0, [0; 10], [0; 10]);
        let t = temp.tile_types.iter().find_map(|(key, value)| if &val == value { Some(key) } else { panic!() });
        t.unwrap().to_owned()
    }
}

pub struct Game {
    item_types: HashMap<String, u32>,
    enemy_types: HashMap<String, u32>,
    time: u32,
    map: [[u32; 100]; 100],
    current_level: u32,
    player: Player,
}

impl Game {
    fn load_level(name: String, map_ar: &mut [[u32; 100]; 100]){
        let level: Vec<char> = fs::read_to_string(name).expect("Could not read level of name {name}").chars().collect();
        for x in 0..100 {
            for y in 0..100 {
                map_ar[x][y] = level[x * 100 + y].to_string().parse().unwrap();
            }
        }
    }

    pub fn new() -> Game {
        let mut g: Game = Game {
            current_level: 0,
            time: 0,
            item_types: HashMap::from([

            ]),
            enemy_types: HashMap::from([

            ]),
            map: [[0; 100]; 100],
            player: Player::new(),
        };
        Game::load_level(g.current_level.to_string(), &mut g.map);
        g
    }

    pub fn play(&mut self) {
        loop {
            
        }
    }
}

fn print_map(map: [[u32; 100]; 100]){
    print!("\x1B[2J\x1B[1;1H");
    for x in 0..100 {
        for y in 0..100 {
            print!("{}", MapTile::get_type(map[x][y]));
        }
    }
}

fn prompt(prompt: &str) -> String {
    print!("{prompt}");
    let mut line: String = String::new();
    io::stdin().read_line(&mut line);
    line
}

fn promptln(prompt_uncomplete: &str) -> String {
    prompt_uncomplete = &format!("{}{}", prompt_uncomplete, "\n");
    let l = prompt(prompt_uncomplete);
    l
}

fn prompt_yesno(prompt: &str, default: bool) -> bool
{
    if default {
        println!("{prompt} [Y/n]");
    }
    else {
        println!("{prompt} [y/N]");
    }
    let mut line: String = String::new();
    io::stdin().read_line(&mut line);
    if line.contains("y") {
        return true;
    }
    else if line.contains("n") {
        return false;
    }
    else {
        return default;
    }
}

pub fn mapper() {
    let mut map: [[u32; 100]; 100] = [[0; 100]; 100];
    if prompt_yesno("load file?", false) {
        let name = prompt("write the path to the file: ");
        Game::load_level(name, &mut map);
    }
    loop {
        print!("\x1B[2J\x1B[1;1H");
        println!("Current map looks like: ");
        let mut line: String = String::new();
        io::stdin().read_line(&mut line);
    }
}
